
import { _Application } from '../Application'
import Method from './Method'

import DataType from './DataType'
import Field from './Field'

import BeanFactory from '../factory/BeanFactory'
import _daoFactory from '../factory/DaoFactory';

import _EntityAgent from '../dao/EntityAgent'

let wrapRequestMethod = function (target: any, propertyKey: string, m: string, path: string) {

    let cls = target.constructor;
    let fn = target[propertyKey].name;
    cls.prototype.requestList = cls.prototype.requestList || [];
    cls.prototype.requestList.push({
        t: m,
        fn: fn,
        p: path
    })
}

function XPath(param: any) {
    let prefix = param;
    if (!!param) {
        prefix = param + "/";
    }
    return target => {
        let requestList = target.prototype.requestList || [];
        requestList.forEach(el => {
            //解析path，识别Restful参数 
            let path = prefix + el.p;
            let segment = path.split('/');
            let _path = [];
            let _params = [];
            for (let i = 0; i < segment.length; i++) {
                let sg = segment[i];
                if (!!sg) {
                    if (sg.startsWith(':')) {
                        let sign = sg.substring(1);
                        _params.push({ index: i, key: sign });
                        sg = '*';
                    }
                    _path.push(sg)
                }
            }
            path = _path.join('/');

            _Application.getRequestMap().addRequestMap(el.t, path, _params, el.fn, BeanFactory.getBean(target));
        });
    }
}

function XTable(table?: string) {
    return target => {
        let entity = target.prototype;
        let fields = entity['fields']
        //建立表模型
        _EntityAgent.emit('_ENTITY_DDL_UPDATE', table, fields);

        //自动生成save .remove 方法 
        let keyRecord = fields.find(function (val, index) {
            return val.isKey;
        })

        entity['getBeanJSON'] = function () {
            let ik = Object.assign({}, this);
            delete ik['__dirty__'];
            return ik;
        }

        entity['fill'] = function (id, cb?: Function) {
            let self = this
            return new Promise(function (resolve, reject) {
                _EntityAgent.emit('_ENTITY_FILL', self, fields, table, id, function (err, _entity) {
                    cb && cb(err, _entity)
                    if (err) {
                        reject(err)
                    } else {
                        resolve(_entity)
                    }
                })
            })
        }

        entity['save'] = function (cb?: Function) {
            let self = this;
            return new Promise(function (resolve, reject) {
                _EntityAgent.emit('_ENTITY_SAVE', self, fields, keyRecord, table, function (err, _entity) {
                    cb && cb(err, _entity)
                    if (err) {
                        reject(err)
                    } else {
                        resolve(_entity)
                    }
                })
            })

        }
        
        entity['remove'] = function (cb?: Function) {
            if (!keyRecord) {
                throw new Error('no unique id');
            }
            let self = this;
            return new Promise(function (resolve, reject) {
                _EntityAgent.emit('_ENTITY_DELETE', self, keyRecord, table, function (err, _entity) {
                    cb && cb(err, _entity)
                    if (err) {
                        reject(err)
                    } else {
                        resolve(_entity)
                    }
                })
            })
        }
    }
}

function XField(field?: string, dataType?: any, options?: { length?: number, isKey?: boolean, describe?: string }) {
    return (target, propertyKey) => {
        target['fields'] = target['fields'] || [];
        let f: Field = {
            field: field || propertyKey,
            propertyKey: propertyKey,
            dataType: dataType || DataType.String,
            length: (options && options.length) ? options.length : 64,
            isKey: (options && options.isKey) ? true : false,
            describe: (options && options.describe)
        }
        target['fields'].push(f);
    }
}

function XResource(res: any) {
    return (target, propertyKey) => {
        target[propertyKey] = BeanFactory.getBean(res);
    }
}

function XGet(value: any) {
    return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
        wrapRequestMethod(target, propertyKey, Method.GET, value);
    }
}

function XPost(value: any) {
    return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
        wrapRequestMethod(target, propertyKey, Method.POST, value);
    }
}

//=================================================================================

function XInjectDao(engine: string) {
    return target => {
        target.prototype['_session'] = _daoFactory.createDao(engine);
    }
}

export { XPath, XGet, XPost, XResource, XInjectDao, XTable, XField }